/*
 * bitmap.cpp
 *
 *  Created on: 2013/07/04
 *      Author: fit
 */

#include "bitmap.h"

#include <cassert>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>

//uint bitmap::COLOR_BYTES = sizeof(color_t);

#define GREY(r, g, b) ((int)(r * 0.3 + g * 0.59 + b * 0.11))

#define INDEX(x, y) (m_width * COLOR_BYTES * (y) + COLOR_BYTES * (x))

bitmap::bitmap()
: m_bitmap(NULL)
, m_width(0)
, m_height(0)
, m_difmap(NULL)
, m_element(NULL)
{}

bitmap::bitmap(size_t width, size_t height)
: m_width(width)
, m_height(height)
, m_difmap(NULL)
, m_element(NULL)
{
	m_bitmap = (color_t*)calloc(m_width * m_height, COLOR_BYTES);
	assert(m_bitmap != NULL);
}

bitmap::bitmap(size_t width, size_t height, u_char* data, uint comp/* = 4*/)
: m_width(width)
, m_height(height)
, m_difmap(NULL)
, m_element(NULL)
{
	assert(comp <= 4);

	m_bitmap = (color_t*)calloc(m_width * m_height, COLOR_BYTES);
	assert(m_bitmap != NULL);

	for (size_t y = 0; y < height; y++)
	for (size_t x = 0; x < width; x++)
	{
		for (uint c = 0; c < comp; c++)
		{
			m_bitmap[y * width + x] <<= __CHAR_BIT__;
			m_bitmap[y * width + x] |= data[(y * width + x) * comp + c];
		}
	}
}

bitmap::bitmap(const bitmap& _bitmap)
: m_width(_bitmap.m_width)
, m_height(_bitmap.m_height)
, m_difmap(NULL)
, m_element(NULL)
{
	m_bitmap = (color_t*)malloc(m_width * m_height * COLOR_BYTES);
	assert(m_bitmap != NULL);
	memcpy(m_bitmap, _bitmap.m_bitmap, m_width * m_height * COLOR_BYTES);
	if (_bitmap.m_difmap)
	{
		m_difmap = (color_t*)malloc(m_width * m_height * COLOR_BYTES);
		assert(m_difmap != NULL);
		memcpy(m_difmap, _bitmap.m_difmap, m_width * m_height * COLOR_BYTES);
	}
}

bitmap::~bitmap()
{
	if (m_bitmap) free(m_bitmap);
	if (m_difmap) free(m_difmap);
	if (m_element) free(m_element);
}

void bitmap::operator=(const bitmap& _bitmap)
{
	m_width = _bitmap.m_width;
	m_height = _bitmap.m_height;
	if (m_bitmap) free(m_bitmap);
	if (m_difmap) free(m_difmap);

	if (m_element) free(m_element);
	m_element = NULL;

 	m_bitmap = (color_t*)malloc(m_width * m_height * COLOR_BYTES);
	assert(m_bitmap != NULL);
	memcpy(m_bitmap, _bitmap.m_bitmap, m_width * m_height * COLOR_BYTES);
	if (_bitmap.m_difmap)
	{
		m_difmap = (color_t*)malloc(m_width * m_height * COLOR_BYTES);
		assert(m_difmap != NULL);
		memcpy(m_difmap, _bitmap.m_difmap, m_width * m_height * COLOR_BYTES);
	}
	else
	{
		m_difmap = NULL;
	}
}

color_t* bitmap::operator[](size_t y_index)
{
	assert(y_index < m_height);
	return &m_bitmap[y_index * m_width];
}

bitmap bitmap::operator*(float scale)
{
	bitmap result((int)(m_width * scale), (int)(m_height * scale));
	for (size_t y = 0; y < result.m_height; y++)
	for (size_t x = 0; x < result.m_width; x++)
	{

	}

	return result;
}



const color_t* bitmap::create_difmap()
{
	if (!m_difmap)
		m_difmap = (color_t*)calloc(m_width * m_height, COLOR_BYTES);
	assert(m_difmap != NULL);

	u_char* source = (u_char*)m_bitmap;
	u_char* destination = (u_char*)m_difmap;

	for (size_t y = 0; y < m_height - 1; y++)
	for (size_t x = 0; x < m_width - 1; x++)
	{
		// max byte value
		u_char h_dif[COLOR_BYTES] = { 0 };
		u_char v_dif[COLOR_BYTES] = { 0 };



		for (uint i = 0; i < COLOR_BYTES; i++)
		{
			h_dif[i] = source[INDEX(x, y) + i] > source[INDEX(x + 1, y) + i] ? source[INDEX(x, y) + i] - source[INDEX(x + 1, y) + i] : 0;
			v_dif[i] = source[INDEX(x, y) + i] > source[INDEX(x, y + 1) + i] ? source[INDEX(x, y) + i] - source[INDEX(x, y + 1) + i] : 0;

			//destination[m_width * COLOR_BYTES * y + COLOR_BYTES * x + i] = ~(h_dif[i] > v_dif[i] ? h_dif[i] : v_dif[i]);
		}

#define GREY_RGB(rgb) GREY(rgb[2], rgb[1], rgb[0])
		memcpy(&destination[INDEX(x, y)], (GREY_RGB(h_dif) > GREY_RGB(v_dif) ? h_dif : v_dif), COLOR_BYTES);
#undef GREY_RGB
	}

	return m_difmap;
}

const color_t* bitmap::create_difmapclean()
{
	if (!m_difmap) create_difmap();

	if (!m_difmap_clean)
		m_difmap_clean = (color_t*)calloc(m_width * m_height, COLOR_BYTES);
	assert(m_difmap_clean != NULL);


	return m_difmap_clean;
}


int bitmap::analyze()
{
	// TODO: analyze diff map.
	for (size_t y = 0; y < m_height - 1; y++)
	for (size_t x = 0; x < m_width - 1; x++)
	{
		// check color
		color_t cur = m_difmap[m_width * y + x];

		u_char* color = (u_char*)&cur;
		u_char* max_byte = std::max_element(&color[0], &color[3]);

		if (*max_byte > 0x20)
		{
			printf("point(%lu, %lu) \n", x, y);
		}
	}

	// TODO: get basic graphic.

	return 0;
}

int bitmap::analyze(uint x, uint y)
{
	if (x < m_width && y < m_height)
		printf("color = 0x%08X\n", m_difmap[m_width * y + x]);
	return 0;
}
